/*
 * Copyright 2011 Mark Davidson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.dctmcommons.impl;

import java.io.PrintWriter;
import java.util.Map;

import org.dctmcommons.ISessionHelper;

import com.documentum.fc.client.IDfModule;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfId;
import com.documentum.fc.methodserver.DfMethodArgumentManager;
import com.documentum.fc.methodserver.DfStandardJobArgumentNames;
import com.documentum.fc.methodserver.IDfMethod;


/**
 * Abstract method that can be hot-deployed via BOF.
 */
public abstract class AbstractMethod implements IDfModule, IDfMethod {
	
	/** Default encoding scheme. */
	private static final String DEFAULT_ENCODING_SCHEME = "UTF-8";

	/** The method arguments. */
	@SuppressWarnings("rawtypes")
	private Map methodArgs = null;
	
	/** The print writer instance. */
	private PrintWriter out = null;
	
	/** Method arg manager - used to parse method args. */
	private DfMethodArgumentManager argManager = null;
	
	/**
	 * The key for the password parameter.
	 * @deprecated Use {@link KEY_TICKET}
	 */
	private static final String KEY_PASSWORD = "password";
	
	/**
	 * The key for the ticket parameter.
	 */
	private static final String KEY_TICKET = "ticket";
	
	/** The key for the domain parameter. */
	private static final String KEY_DOMAIN = "domain";
	
	/** The session manager. */
	private IDfSessionManager sessionManager = null;
	
	/** The session. */
	private IDfSession session = null;
	
	/** The session helper. */
	private ISessionHelper sessionHelper = SessionHelper.getInstance();
	
	/*
	 * (non-Javadoc)
	 * @see com.documentum.fc.methodserver.IDfMethod#execute(java.util.Map, java.io.PrintWriter)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final int execute(final Map args, final PrintWriter pw)
		throws Exception {
		
		argManager = new DfMethodArgumentManager(args);
		methodArgs = args;
		out = pw;
		
		return executeMethod();
	}
	
	/**
	 * Execute the method
	 * @return
	 * @throws Exception The exception
	 */
	protected abstract int executeMethod() throws Exception;
	
	/**
	 * Gets the job instance.
	 * @return The job instance
	 * @throws DfException The repository exception
	 */
	protected IDfSysObject getJob() throws DfException {
		final String jobId = getJobId();
		if (jobId != null) {
			return (IDfSysObject) getSession().getObject(new DfId(jobId));
		} else {
			return null;
		}
	}
	
	/**
	 * Performs the cleanup routine - closes all resources (e.g. session).
	 */
	protected void cleanup() {
		releaseSession();
		closeOuput();
	}
	
	/**
	 * Releases the current session.
	 */
	protected void releaseSession() {
		if (session != null) {
			sessionManager.release(session);
			trace(5, "Released session");
		}
	}
	
	/**
	 * Closes the output.
	 */
	protected void closeOuput() {
		if (out != null) {
			out.flush();
			out.close();
		}
	}
	
	/**
	 * Gets or creates a session.
	 * @return The session
	 * @throws DfException The repository exception
	 */
	protected IDfSession getSession() throws DfException {
		if (session == null) {
			trace(5, "Creating session..");
			session = getSessionManager().getSession(getRepositoryName());
		}
		return session;
	}
	
	/**
	 * Gets or creates a session manager.
	 * @return The session manager
	 * @throws DfException The repository exception
	 */
	protected IDfSessionManager getSessionManager() throws DfException {
		if (sessionManager == null) {
			trace(5, "Creating session manager..");
			sessionManager = sessionHelper.createSessionManager(
														getRepositoryName(),
														getUsername(),
														getPassword(),
														getDomain());
		}
		return sessionManager;
	}

	/**
	 * Writes a trace message.
	 * @param traceLevel The trace level
	 * @param msg The message
	 */
	protected void trace(final int traceLevel, final String msg) {
		if (traceLevel <= getTraceLevel()) {
			if (out != null) {
				out.println(msg);
			} else {
				System.out.println(msg);
			}
		}
	}
	
	/**
	 * Gets the specified parameter.
	 * @param paramName The parameter name
	 * @return The parameter value
	 */
	private String[] getParameterValues(final String paramName) {
		if (methodArgs != null) {
			for (final Object key : methodArgs.keySet()) {
				final String strKey = (String) key;
				if (strKey.equals(paramName)) {
					return (String[]) methodArgs.get(key);
				}
			}
		} else {
			trace(0, "No method arguments to parse!");
		}
		return null;
	}
	
	/**
	 * Gets the parameter value.
	 * @param paramName The parameter name
	 * @return The parameter value
	 */
	protected String getParameterValue(final String paramName) {
		
		// Using DfMethodArgumentManager to parse arguments now
		final String[] values = getParameterValues(paramName);
		if (values != null && values.length >= 1) {
			return values[0];
		} else {
			return null;
		}
		
		/*
		String paramValue = null;
		String decodedParamValue = null;
		
		try {
			paramValue = argManager.getString(paramName);
			paramValue = URLDecoder.decode(paramValue, DEFAULT_ENCODING_SCHEME);
		} catch (DfMethodArgumentException mae) {
			trace(0, mae.getLocalizedMessage());
		} catch (UnsupportedEncodingException uee) {
			trace(0, uee.getLocalizedMessage());
		}
		return decodedParamValue;
		*/
	}

	/**
	 * Gets the username.
	 * @return The username
	 */
	protected String getUsername() {
		return getParameterValue(DfStandardJobArgumentNames.USER_NAME);
	}
	
	/**
	 * Gets the ticket.
	 * @return The ticket
	 */
	protected String getTicket() {
		return getParameterValue(KEY_TICKET);
	}
	
	/**
	 * Gets the password.
	 * @return The password
	 * @deprecated Use the getTicket method instead
	 */
	protected String getPassword() {
		return getParameterValue(KEY_PASSWORD);
	}

	/**
	 * Gets the domain.
	 * @return The domain
	 */
	protected String getDomain() {
		return getParameterValue(KEY_DOMAIN);
	}
	
	/**
	 * Gets the repository name.
	 * @return The repository name
	 */
	protected String getRepositoryName() {
		return getParameterValue(DfStandardJobArgumentNames.DOCBASE_NAME);
	}
	
	/**
	 * Gets the job id.
	 * @return The job id
	 */
	protected String getJobId() {
		return getParameterValue(DfStandardJobArgumentNames.JOB_ID);
	}
	
	/**
	 * Gets the trace level.
	 * @return The trace level
	 */
	protected int getTraceLevel() {
		final String strTraceLevel = getParameterValue(
							DfStandardJobArgumentNames.METHOD_TRACE_LEVEL);
		int traceLevel = 0;
		try {
			traceLevel = Integer.parseInt(strTraceLevel);
		} catch(NumberFormatException e) {}
		
		return traceLevel;
	}
}
